//
// Created by yunnan xu on 2020/12/14.
//

#include "SkyBoxPass.h"
#include "Pass.h"
#include "Scene.h"
#include "RenderItem.h"
#include "RenderItemStaticOpaque.h"
#include "ResourceMgr.h"
#include "Texture.h"
#include "DummyModel.h"
#include "Scene.h"
#include "Camera.h"
#include "Model.h"
#include "EngineCore.h"
#include "GLESUtils.h"
#include <EGL/egl.h>
#include <GLES3/gl32.h>
#include <memory>


SkyBoxPass<GraphicsAPI::GLESv3>::SkyBoxPass(std::vector<const char *> cube_map_file_path_list)
{
    cube_texture = std::make_shared<CubeMapTexture<GraphicsAPI::GLESv3>>(cube_map_file_path_list, 0);
    InitSkyBoxRenderItem();
}

void SkyBoxPass<GraphicsAPI::GLESv3>::InitShaderUniformLocation()
{
    modelToWorldMatrix_location = glGetUniformLocation(program, "modelToWorldMatrix");
    skybox_location = glGetUniformLocation(program, "skybox");
}

void SkyBoxPass<GraphicsAPI::GLESv3>::Draw()
{
    GL_CHECK(glDepthMask(GL_FALSE));
    GL_CHECK(glDisable(GL_CULL_FACE));
    GL_CHECK(glUseProgram(program));
    auto main_cam = SceneMgr::GetInstance()->GetCurrentScene()->GetMainCamera();
    auto vp_matrix = main_cam->GetProjMatrix() * main_cam->GetViewMatrix();
    auto mvp_matrix = vp_matrix * skybox_item->GetModel()->GetModelMatrix();

    GLfloat * pSource = glm::value_ptr(mvp_matrix);
    GL_CHECK(glUniformMatrix4fv(3, 1, false, pSource));
    GL_CHECK(glBindVertexArray(skybox_item->GetVAO()));
    GL_CHECK(glActiveTexture(cube_texture->GetTextureUnit()));
    GL_CHECK(glBindTexture(GL_TEXTURE_CUBE_MAP, cube_texture->GetTexture()));
    GL_CHECK(glDrawElements(GL_TRIANGLES, 2 * 6 * 3, skybox_item->GetModel()->GetIndexType(), 0));
    GL_CHECK(glBindVertexArray(0));
    GL_CHECK(glEnable(GL_CULL_FACE));
    GL_CHECK(glDepthMask(GL_TRUE));
}

void SkyBoxPass<GraphicsAPI::GLESv3>::InitSkyBoxRenderItem()
{
    skybox_item = std::make_shared<RenderItemStaticOpaque<GraphicsAPI::GLESv3>>();
    skybox_item->LoadDummyData(DummyItemType::Box);

    skybox_item->AppendTexture(cube_texture);

    auto cur_scene = SceneMgr::GetInstance()->GetCurrentScene();
    cur_scene->SetSkyboxItem(skybox_item);
}